<template>
	<view class="view-grid">
		<view class="fx-height"></view>
		<view class="fx-header">
			<view class="fx-header-total">
				<text>共</text><text class="fx-header-row-total">{{ rowTotal }}</text><text>条数据</text>
			</view>
			<view 
				v-for="(btn, index) in fabButtons" 
				:key="index"
				v-if="!btn.hidden"
				class="btn-item"
				@click="griFabBtnClick(btn)"
			>
				<u-icon :name="btn.icon" :size="btn.size || 18"></u-icon>
				<view>{{ btn.name }}</view>
			</view>
		</view>
		<slot name="gridHeader"></slot>
		
		<!-- 表格数据 -->
		<view class="view-grid-list">
			<vol-table 
				v-if="isCreated" 
				:class="[className]" 
				:url="tableUrl" 
				:defaultLoadPage="load" 
				:index="rowIndex" 
				:ck="ck"
				:direction="direction" 
				:titleField="titleField"
				:height="height" 
				:columns="columns" 
				:textInline="textInline"
				ref="tableRef"
				@cellClick="gridCellClick"
				@rowButtons="getRowButtons" 
				@rowButtonClick="gridRowButtonClick" 
				@rowClick="gridRowClick"
				@loadBefore="loadGridTableBefore" 
				@loadAfter="loadGridTableAfter" 
				@formatter="cellFormatter"
			>
			</vol-table>
			<slot name="gridFooter"></slot>
		</view>
		
		<!-- 搜索弹窗 -->
		<u-popup :show="searchModel" @close="searchModel = false" @touchmove.prevent :zIndex="999999">
			<view class="vol-action-sheet-select-container" :style="{ 'max-height': maxHeight + 'px' }">
				<view class="vol-action-sheet-select-title">
					搜索
					<view class="f-icon" @click="searchModel = false">取消</view>
				</view>
				<slot name="searchHeader"></slot>
				<view class="vol-action-sheet-select-content">
					<view class="search-item" @click="sortSelectModel = true">
						<view class="f-form-label">排序字段</view>
						<view style="flex:1;">
							<view style="color:rgb(192 196 204);font-size:15px;" v-show="!sortField">
								请选择排序字段
							</view>
							<view style="font-size:15px;" v-show="sortField">
								{{ sortName }}
							</view>
						</view>
						<u-icon name="arrow-right"></u-icon>
					</view>
					<view class="search-item" style="margin-bottom: 20rpx;">
						<view class="f-form-label">排序方式</view>
						<view style="flex:1;">
							<u-radio-group v-model="orderType" placement="row">
								<u-radio :customStyle="{ 'margin-right': '20px' }" label="降序" name="desc"></u-radio>
								<u-radio :customStyle="{ 'margin-right': '20px' }" label="升序" name="asc"></u-radio>
							</u-radio-group>
						</view>
					</view>
					<vol-form 
						:load-key="false" 
						ref="searchFormRef" 
						:form-options="searchFormOptions" 
						:formFields="searchFormFields"
						@onChange="searchGridFormOnChange"
					>
					</vol-form>
					<view class="search-btns">
						<view class="btn">
							<u-button @click="resetSearchForm()" :customStyle="{ 'border-radius': '6px' }" type="success" icon="reload" text="重置"></u-button>
						</view>
						<view class="btn">
							<u-button @click="searchClick" :customStyle="{ 'border-radius': '6px' }" type="primary" icon="search" text="搜索"></u-button>
						</view>
					</view>
				</view>
			</view>
		</u-popup>
		
		<!-- 排序选择弹窗 -->
		<view class="sort-form-popup">
			<u-popup :show="sortSelectModel" @close="sortSelectModel = false" @touchmove.prevent :zIndex="9999999">
				<view class="vol-action-sheet-select-container" style="max-height:400px">
					<view class="vol-action-sheet-select-title">请选择排序</view>
					<view class="search-action-sheet-select-content">
						<view 
							v-for="(item, index) in searchFormOptions" 
							:key="index"
							v-show="item.type !== 'group'" 
							@click="sortSelectClick(item)" 
							class="serch-action-sheet-select-item"
						>
							{{ item.title }}
						</view>
					</view>
				</view>
			</u-popup>
		</view>
		
		<!-- 新建编辑弹窗 -->
		<u-popup :show="model" @close="model = false" @touchmove.prevent :zIndex="999999">
			<view class="vol-action-sheet-select-container" :style="{ 'max-height': maxHeight + 'px' }">
				<view class="vol-action-sheet-select-title">
					{{ buttons.length ? (currentAction === 'Add' ? '新增' : '编辑') : '基本信息' }}
					<view class="f-icon" @click="model = false">取消</view>
				</view>
				<slot name="modelHeader"></slot>
				<view class="vol-action-sheet-select-content">
					<vol-form 
						:labelWidth="labelWidth" 
						:load-key="false"
						ref="editFormRef" 
						:form-options="editFormOptions"
						:formFields="editFormFields"
						@input-confirm="inputConfirm"
						@onChange="editGirdFormOnChange"
						@extraClick="gridExtraClick"
						@uploadBefore="editGridFormUploadBefore"
					>
					</vol-form>
				</view>
				<slot name="modelBody"></slot>
				<view class="btns" :class="{ 'l-btn': buttons.length > 4 }">
					<view v-for="(btn, index) in buttons" :key="index" v-show="!btn.hidden" class="btn">
						<u-button @click="btnClick(btn)" :customStyle="{ 'border-radius': '6px' }" :type="btn.type" :icon="btn.icon" :text="btn.name"></u-button>
					</view>
					<view style="padding: 0 20rpx;width: 100%;" v-if="!buttons.length">
						<u-button @click="model = false" :customStyle="{ 'border-radius': '6px' }" type="primary" text="关 闭"></u-button>
					</view>
				</view>
				<slot name="modelFooter"></slot>
			</view>
		</u-popup>
		
		<!-- 删除确认弹窗 -->
		<view class="grid-u-model">
			<u-modal 
				:show="showDel" 
				cancelText="取消" 
				:showCancelButton="true" 
				:showConfirmButton="true"
				@cancel="cancelDel" 
				@confirm="confirmDel" 
				title="警告"
			>
				<view style="color: red;">确定要删除此数据吗!</view>
			</u-modal>
		</view>
	</view>
</template>

<script setup lang="ts">
import { ref, reactive, computed, onMounted, getCurrentInstance, defineProps, defineEmits, defineExpose } from 'vue'
import type { Ref, ComponentInternalInstance } from 'vue'

// 类型定义
interface GridColumn {
	field: string
	title: string
	width?: number
	hidden?: boolean
	link?: boolean
	summary?: boolean
	bind?: {
		key: string
		data: any[]
	}
	type?: string
	[key: string]: any
}

interface FormOption {
	field: string
	title: string
	type: string
	required?: boolean
	readonly?: boolean
	data?: any[]
	key?: string
	dataKey?: string
	range?: boolean
	[key: string]: any
}

interface GridButton {
	name: string
	icon: string
	value: string
	hidden?: boolean
	type: string
	size?: string | number
	color?: string
	onClick: () => void
}

interface GridOptions {
	columns: GridColumn[]
	detail?: any[]
	editFormFields: Record<string, any>
	editFormOptions: FormOption[]
	searchFormFields: Record<string, any>
	searchFormOptions: FormOption[]
	table: {
		name?: string
		url: string
		key: string
	}
	extend?: () => {
		methods?: Record<string, Function>
	}
}

interface PermissionItem {
	tableName: string
	permission: string
}

interface DictionaryResponse {
	dicNo: string
	data: any[]
}

// Props
const props = defineProps<{
	options: GridOptions
}>()

// Emits
const emit = defineEmits<{
	(e: 'dicInited', data: any): void
	(e: 'onAudit', data: any): void
}>()

// 获取当前实例
const instance = getCurrentInstance() as ComponentInternalInstance

// Refs
const tableRef = ref()
const editFormRef = ref()
const searchFormRef = ref()

// 基础工具函数
const base = {
	isEmpty: (value: any): boolean => {
		if (value === null || value === undefined || value === '') return true
		if (Array.isArray(value)) return value.length === 0
		if (typeof value === 'object') return Object.keys(value).length === 0
		return false
	},
	getDate: (): string => {
		const now = new Date()
		return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`
	},
	getDateTime: (): string => {
		const now = new Date()
		return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}`
	}
}

// HTTP工具函数
const http = {
	get: async (url: string, params: any = {}, loading: boolean = false): Promise<any> => {
		if (loading) {
			uni.showLoading({ title: '加载中...' })
		}
		return new Promise((resolve, reject) => {
			uni.request({
				url: url,
				method: 'GET',
				data: params,
				header: {
					'Authorization': getToken()
				},
				success: (res: any) => {
					if (loading) uni.hideLoading()
					resolve(res.data)
				},
				fail: (err: any) => {
					if (loading) uni.hideLoading()
					reject(err)
				}
			})
		})
	},
	post: async (url: string, data: any = {}, loading: boolean | string = false): Promise<any> => {
		if (loading) {
			const title = typeof loading === 'string' ? loading : '提交中...'
			uni.showLoading({ title })
		}
		return new Promise((resolve, reject) => {
			uni.request({
				url: url,
				method: 'POST',
				data: data,
				header: {
					'Authorization': getToken(),
					'Content-Type': 'application/json'
				},
				success: (res: any) => {
					if (loading) uni.hideLoading()
					resolve(res.data)
				},
				fail: (err: any) => {
					if (loading) uni.hideLoading()
					reject(err)
				}
			})
		})
	},
	ipAddress: ''
}

// Store相关函数
const getToken = (): string => {
	return uni.getStorageSync('token') || ''
}

const getMenu = (): any[] => {
	return uni.getStorageSync('menu') || []
}

const setPermission = (data: any): void => {
	uni.setStorageSync('menu', data)
}

// State
const rowTotal = ref<number>(0)
const isWx = ref<boolean>(false)
const className = ref<string>(`vol-table-${Math.floor(Math.random() * 1000000)}`)
const rowIndex = ref<boolean>(false)
const load = ref<boolean>(true)
const height = ref<number>(0)
const direction = ref<'list' | 'horizontal'>('list')
const titleField = ref<string>('')
const fabButtons = ref<GridButton[]>([])
const currentAction = ref<'Add' | 'Update'>('Add')
const currentRow = ref<Record<string, any>>({})
const maxHeight = ref<number>(0)
const model = ref<boolean>(false)
const showFabButons = ref<boolean>(true)
const showButtons = ref<boolean>(true)
const textInline = ref<boolean>(true)
const columns = ref<GridColumn[]>([...props.options.columns])
const editFormFields = reactive<Record<string, any>>(JSON.parse(JSON.stringify(props.options.editFormFields)))
const searchFormOptions = ref<FormOption[]>([...props.options.searchFormOptions])
const searchFormFields = reactive<Record<string, any>>(JSON.parse(JSON.stringify(props.options.searchFormFields)))
const editFormOptions = ref<FormOption[]>([...props.options.editFormOptions])
const permission = ref<PermissionItem[]>([])
const buttons = ref<GridButton[]>([])
const hasEditpermission = ref<boolean>(false)
const searchModel = ref<boolean>(false)
const sortField = ref<string>('')
const sortName = ref<string>('')
const orderType = ref<'desc' | 'asc'>('desc')
const sortSelectModel = ref<boolean>(false)
const tableUrl = ref<string>(props.options.table.url)
const tableAction = ref<string>('')
const showDel = ref<boolean>(false)
const isCreated = ref<boolean>(false)
const labelWidth = ref<number>(80)
const ck = ref<boolean>(false)

const visibleFabButtons = computed(() => {
	return fabButtons.value.filter(btn => !btn.hidden)
})

// Methods
const onInited = (): void => {
	console.log("viewgridinit")
	emit('dicInited', [])
}

const onTableCreated = (): void => {
	onInited()
}

const cellFormatter = (row: any, column: GridColumn, index: number, callback: Function): void => {
	const methods = props.options.extend?.()?.methods
	if (methods?.formatter) {
		return callback(methods.formatter(row, column, index))
	}
	return callback(row[column.field])
}

const gridRowClick = (index: number, row: any, columns: GridColumn[]): void => {
	currentRow.value = row
	currentAction.value = 'Update'
	hiddenDelButton(false)
	
	editFormOptions.value.forEach(x => {
		if (x.type === 'radio' && x.data && x.data.length) {
			if (row && Object.keys(row).length) {
				if (typeof x.data[0].key === 'string') {
					row[x.field] = String(row[x.field])
				} else {
					row[x.field] = Number(row[x.field])
				}
			}
		}
	})
	
	if (editFormRef.value) {
		editFormRef.value.reset(row)
	} else {
		resetEditForm(row)
	}
	
	const methods = props.options.extend?.()?.methods
	if (methods?.rowClick && !methods.rowClick(index, row, columns)) {
		return
	}
	
	if (modelOpenBefore(row) && modelOpenAfter(row)) {
		model.value = true
	}
}

const gridCellClick = (index: number, row: any, column: GridColumn): void => {
	const methods = props.options.extend?.()?.methods
	if (methods?.cellClick && !methods.cellClick(index, row, column)) {
		return
	}
}

const hiddenDelButton = (hidden: boolean): void => {
	const delButton = buttons.value.find(x => x.value === 'del')
	if (delButton) {
		delButton.hidden = hidden
	}
}

const gridAdd = (): void => {
	currentAction.value = 'Add'
	hiddenDelButton(true)
	resetEditForm()
	if (modelOpenBefore(null) && modelOpenAfter(null)) {
		model.value = true
	}
}

const resetEditForm = (source?: any): void => {
	if (editFormRef.value) {
		editFormRef.value.reset(source)
		return
	}
	resetGridForm(editFormFields, source, props.options.editFormOptions)
}

const btnClick = (btn: GridButton): void => {
	btn.onClick.call(null)
}

const modelOpenBefore = (row: any): boolean => {
	const methods = props.options.extend?.()?.methods
	return methods?.modelOpenBefore ? methods.modelOpenBefore(row) : true
}

const modelOpenAfter = (row: any): boolean => {
	const methods = props.options.extend?.()?.methods
	return methods?.modelOpenAfter ? methods.modelOpenAfter(row) : true
}

const showSearch = (): void => {
	searchModel.value = true
}

const resetGridForm = (formFields: Record<string, any>, source: any, formOptions: FormOption[]): void => {
	for (const key in formFields) {
		if (source && source.hasOwnProperty(key)) {
			formFields[key] = source[key]
		} else {
			if (Array.isArray(formFields[key])) {
				formFields[key].splice(0)
				if (formOptions.some(x => x.field === key && x.range)) {
					formFields[key].push('', '')
				}
			} else {
				formFields[key] = ''
			}
		}
	}
}

const resetSearchForm = (): void => {
	sortField.value = ''
	sortName.value = ''
	resetGridForm(searchFormFields, null, props.options.searchFormOptions)
}

const searchClick = (): void => {
	searchModel.value = false
	refresh()
}

const search = (): void => {
	refresh()
}

const refresh = (): void => {
	if (tableRef.value?.load) {
		tableRef.value.load(null, true)
	}
}

const sortSelectClick = (item: FormOption): void => {
	sortField.value = item.field
	sortName.value = item.title
	sortSelectModel.value = false
}

const editGirdFormOnChange = (field: string, value: any, item: any): void => {
	const methods = props.options.extend?.()?.methods
	methods?.editFormOnChange?.(field, value, item)
}

const editGridFormUploadBefore = (fields: any, option: any, done: Function): void => {
	const methods = props.options.extend?.()?.methods
	if (methods?.uploadBefore) {
		return methods.uploadBefore(fields, option, done)
	}
	done()
}

const searchGridFormOnChange = (field: string, value: any, item: any): void => {
	const methods = props.options.extend?.()?.methods
	methods?.searchFormOnChange?.(field, value, item)
}

const getSearchItem = (field: string): string | undefined => {
	const data = searchFormOptions.value.find(x => x.field === field)
	return data?.type
}

const getSearchParameters = (): { wheres: any[] } => {
	const query = {
		wheres: [] as any[]
	}
	
	for (const key in searchFormFields) {
		let value = searchFormFields[key]
		if (base.isEmpty(value)) continue
		
		if (typeof value === 'number') {
			value = String(value)
		}
		
		const displayType = getSearchItem(key)
		
		if (displayType === 'cascader' && Array.isArray(value)) {
			value = value.length ? String(value[value.length - 1]) : ''
		}
		
		if (typeof value === 'string' || ['date', 'datetime', 'range'].indexOf(displayType || '') === -1) {
			query.wheres.push({
				name: key,
				value: typeof value === 'string' ? value.trim() : value.join(','),
				displayType: displayType
			})
			continue
		}
		
		for (let index = 0; index < value.length; index++) {
			if (!base.isEmpty(value[index])) {
				query.wheres.push({
					name: key,
					value: (value[index] + '').trim(),
					displayType: (() => {
						if (['date', 'datetime', 'range'].indexOf(displayType || '') !== -1) {
							return index ? 'lessorequal' : 'thanorequal'
						}
						return displayType
					})()
				})
			}
		}
	}
	
	return query
}

const loadGridTableBefore = (param: any, callback: Function): void => {
	param.wheres = getSearchParameters().wheres
	if (orderType.value) {
		param.order = orderType.value
	}
	if (sortField.value) {
		param.sort = sortField.value
	}
	
	const methods = props.options.extend?.()?.methods
	if (methods?.searchBefore && !methods.searchBefore(param)) {
		return callback(false)
	}
	callback(true)
}

const loadGridTableAfter = (data: any, callback: Function): void => {
	rowTotal.value = data.total
	const methods = props.options.extend?.()?.methods
	if (methods?.searchAfter && !methods.searchAfter(data.rows, data)) {
		return callback(false)
	}
	callback(true)
}

const gridDel = (): void => {
	showDel.value = true
}

const cancelDel = (): void => {
	showDel.value = false
}

const confirmDel = async (): Promise<void> => {
	const url = 'api' + props.options.table.url + 'del'
	const key = currentRow.value[props.options.table.key]
	
	const methods = props.options.extend?.()?.methods
	if (methods?.delBefore && !methods.delBefore(key, currentRow.value)) {
		return
	}
	
	try {
		const result = await http.post(url, [key], true)
		uni.showToast({ title: result.message, icon: 'none' })
		showDel.value = false
		
		if (!result.status) {
			return
		}
		
		model.value = false
		refresh()
		methods?.delAfter?.(key, currentRow.value)
	} catch (error) {
		console.error(error)
		uni.showToast({ title: '删除失败', icon: 'none' })
	}
}

const gridSave = async (): Promise<void> => {
	if (!editFormRef.value?.validate()) {
		return
	}
	
	const editFormFieldsData: Record<string, any> = {}
	editFormFieldsData[props.options.table.key] = currentRow.value[props.options.table.key]
	
	for (const key in editFormFields) {
		const _val = editFormFields[key]
		if (Array.isArray(_val)) {
			if (editFormOptions.value.some(x => x.field === key && x.type === 'img')) {
				const imgs = _val.filter(c => c.orginUrl).map(m => m.orginUrl).join(',')
				editFormFieldsData[key] = imgs
			} else {
				editFormFieldsData[key] = _val.join(',')
			}
		} else {
			editFormFieldsData[key] = _val
		}
	}
	
	const formData = {
		mainData: editFormFieldsData,
		detailData: null,
		delKeys: null
	}
	
	const methods = props.options.extend?.()?.methods
	
	if (currentAction.value === 'Add') {
		if (methods?.addBefore && !methods.addBefore(formData)) {
			return
		}
	} else {
		if (methods?.updateBefore && !methods.updateBefore(formData)) {
			return
		}
	}
	
	const url = 'api' + props.options.table.url + currentAction.value
	
	try {
		const result = await http.post(url, formData, true)
		uni.showToast({ title: result.message, icon: 'none' })
		
		if (!result.status) {
			return
		}
		
		refresh()
		
		if (currentAction.value === 'Add') {
			if (methods?.addAfter && !methods.addAfter(result)) {
				return
			}
		} else if (methods?.updateAfter && !methods.updateAfter(result)) {
			return
		}
		
		model.value = false
	} catch (error) {
		console.error(error)
		uni.showToast({ title: '保存失败', icon: 'none' })
	}
}

const initPermissionButtons = (): void => {
	const _permission = permission.value.find(x => 
		x.tableName && (tableAction.value || props.options.table.name || '').toUpperCase() === x.tableName.toUpperCase()
	)?.permission
	
	if (!_permission) {
		return
	}
	
	if (_permission.indexOf('Delete') !== -1) {
		buttons.value.push({
			name: '删除',
			icon: 'close',
			value: 'del',
			hidden: true,
			type: 'error',
			onClick: () => {
				gridDel()
			}
		})
	}
	
	if (_permission.indexOf('Update') !== -1 || _permission.indexOf('Add') !== -1) {
		buttons.value.push(
			{
				name: '重置',
				icon: 'reload',
				value: 'reset',
				hidden: false,
				type: 'success',
				onClick: () => {
					resetEditForm()
				}
			},
			{
				name: '提交',
				icon: 'checkbox-mark',
				value: 'add',
				hidden: false,
				type: 'primary',
				onClick: () => {
					gridSave()
				}
			}
		)
		hasEditpermission.value = true
	} else {
		editFormOptions.value.forEach(x => {
			x.readonly = true
			x.required = false
		})
	}
	
	const fabButtonsList: GridButton[] = [
		{
			icon: 'reload',
			value: 'search',
			name: '刷新',
			size: '18',
			hidden: false,
			color: '#009688',
			onClick: () => {
				refresh()
			}
		},
		{
			icon: 'search',
			value: 'search',
			name: '查询',
			hidden: false,
			size: '20',
			color: 'rgb(7 185 14)',
			onClick: () => {
				showSearch()
			}
		}
	]
	
	if (_permission.indexOf('Add') !== -1) {
		fabButtonsList.unshift({
			icon: 'plus',
			value: 'add',
			hidden: false,
			name: '添加',
			size: '17',
			color: 'rgb(2, 171, 255)',
			onClick: () => {
				gridAdd()
			}
		})
	}
	
	fabButtons.value.push(...fabButtonsList)
}

const initPermission = async (): Promise<void> => {
	let _permission = getMenu()
	if (_permission.length) {
		permission.value = _permission
		initPermissionButtons()
		return
	}
	
	try {
		const result = await http.get('api/menu/getTreeMenu', {}, false)
		permission.value = result.menu ? result.menu : result
		setPermission(result)
		initPermissionButtons()
	} catch (error) {
		console.error(error)
	}
}

const initSource = async (): Promise<void> => {
	let keys: string[] = []
	
	keys.push(...columns.value.filter(x => x.bind?.key && !x.bind.data.length).map(x => x.bind!.key))
	keys.push(...searchFormOptions.value.filter(x => (x.key || x.dataKey) && !x.data?.length).map(x => x.key || x.dataKey || ''))
	keys.push(...editFormOptions.value.filter(x => {
		if (x.type === 'img' || x.type === 'file' || x.type === 'excel') {
			x.url = 'api/' + props.options.table.name + '/upload'
		}
		return (x.key || x.dataKey) && !x.data?.length
	}).map(x => x.key || x.dataKey || ''))
	
	if (!keys.length) {
		return
	}
	
	keys = [...new Set(keys)]
	
	try {
		const result: DictionaryResponse[] = await http.post('api/Sys_Dictionary/GetVueDictionary', keys, false)
		result.forEach((item) => {
			columns.value.forEach(x => {
				if (x.bind?.key === item.dicNo) {
					x.bind.data = item.data
				}
			})
			searchFormOptions.value.forEach(x => {
				if ((x.key || x.dataKey) === item.dicNo) {
					x.data = item.data
				}
			})
			editFormOptions.value.forEach(x => {
				if ((x.key || x.dataKey) === item.dicNo) {
					x.data = item.data
				}
			})
		})
	} catch (error) {
		console.error(error)
	}
}

const initSearchFormDateRange = (): void => {
	searchFormOptions.value.forEach(option => {
		if ((option.type === 'range' || option.type === 'date' || option.type === 'datetime') && !option.hasOwnProperty('range')) {
			if (!Array.isArray(searchFormFields[option.field])) {
				searchFormFields[option.field] = ['', '']
			}
			option.range = true
		}
	})
}

const initFormAttr = (): void => {
	editFormOptions.value.forEach(x => {
		if (!x.hasOwnProperty('readonly')) {
			x.readonly = false
		}
		if (!x.hasOwnProperty('required')) {
			x.required = false
		}
	})
}

const griFabBtnClick = (btn: GridButton): void => {
	btn.onClick()
}

const getRowButtons = (index: number, row: any, callback: Function): any[] => {
	const methods = props.options.extend?.()?.methods
	if (methods?.rowButtons) {
		callback(methods.rowButtons(index, row))
		return methods.rowButtons(index, row)
	}
	callback([])
	return []
}

const gridRowButtonClick = (btn: any, index: number, row: any): void => {
	const methods = props.options.extend?.()?.methods
	methods?.rowButtonClick?.(btn, index, row)
}

const gridExtraClick = (option: any, fields: any): void => {
	const methods = props.options.extend?.()?.methods
	methods?.extraClick?.(option, fields)
}

const inputConfirm = (field: string, e: any): void => {
	console.log(field)
}

// Lifecycle
onMounted(async () => {
	initSearchFormDateRange()
	await initPermission()
	isCreated.value = true
	
	// #ifdef MP-WEIXIN
	isWx.value = true
	// #endif
	
	titleField.value = columns.value.find(x => x.link)?.field || ''
	tableUrl.value = 'api' + props.options.table.url + 'getPageData'
	
	// 延迟初始化（针对微信小程序）
	const initializeComponents = () => {
		onInited()
		initSource()
	}
	
	if (!isWx.value) {
		initializeComponents()
	}
	
	uni.getSystemInfo({
		success: (res) => {
			maxHeight.value = res.screenHeight * 0.82
			
			if (!height.value || height.value < 0) {
				const query = uni.createSelectorQuery().in(instance)
				query.select('.view-grid-list').boundingClientRect((rect: any) => {
					if (rect) {
						let h = 0
						if (columns.value.some(x => x.summary)) {
							h = 49
						}
						height.value = res.windowHeight - rect.top - h
					}
				}).exec()
			}
		}
	})
	
	// 微信小程序延迟初始化
	if (isWx.value) {
		setTimeout(() => {
			initializeComponents()
		}, 100)
	}
})

// Expose
defineExpose({
	refresh,
	search,
	resetSearchForm,
	gridAdd
})
</script>

<style lang="less" scoped>
.view-grid {
	height: 100%;
	overflow: hidden;
	background: #f9f9f9;

	.fx-height {
		height: 70rpx;
	}

	.fx-header {
		padding: 0 20rpx;
		box-sizing: border-box;
		top: 0;
		position: absolute;
		display: flex;
		width: 100%;
		height: 70rpx;
		z-index: 99;
		background: #f7f7f7;
		align-items: center;

		.btn-item {
			height: 100%;
			align-items: center;
			display: flex;
			font-size: 28rpx;
			margin-left: 18rpx;
		}
	}

	.fx-header-total {
		flex: 1;
		font-size: 28rpx;
		color: #555;
		box-sizing: border-box;

		.fx-header-row-total {
			font-weight: bolder;
			font-size: 30rpx;
			margin: 0 6rpx;
		}
	}
}

.vol-action-sheet-select-container {
	min-height: 600rpx;
	display: flex;
	flex-direction: column;

	.vol-action-sheet-select-title {
		padding: 24rpx;
		text-align: center;
		position: relative;
		border-bottom: 1px solid rgb(233 233 233);

		.f-icon {
			position: absolute;
			right: 0rpx;
			top: 0;
			font-size: 28rpx;
			color: #2979FF;
			line-height: 49px;
			height: 47px;
			width: 80px;
			padding-right: 30rpx;
			text-align: right;
		}
	}

	.vol-action-sheet-select-content {
		flex: 1;
		height: 0;
		background: #f7f7f7;
		overflow: scroll;
	}

	.btns {
		display: flex;
		padding: 30rpx 20rpx 40rpx 0;
		background: #f7f7f7;

		.btn {
			flex: 1;
			margin-left: 20rpx;
		}
	}

	.l-btn {
		display: inline-block;
		width: 100%;

		.btn {
			float: left;
			width: 31.5%;
			margin-left: 1.5%;
			margin-top: 20rpx;
		}
	}
}

.search-btns {
	display: flex;
	padding: 30rpx 20rpx 40rpx 0;
	background: #f7f7f7;

	.btn {
		flex: 1;
		margin-left: 20rpx;
	}
}

.search-item {
	display: flex;
	background: #FFFFFF;
	padding: 30rpx 18rpx;
	border-bottom: 1px solid #eee;

	.f-form-label {
		width: 80px;
		position: relative;
		padding-left: 10px;
		color: #4c4c4c;
		font-size: 30rpx;
	}
}

.serch-action-sheet-select-item {
	border-bottom: 1px solid rgb(243 243 243);
	padding: 26rpx;
	text-align: center;
}
</style>